/*
 * gpio1500a.cpp
 *
 *  Created on: 2019年3月28日
 *      Author: westl
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "gpio1500a.h"

static unsigned char *data_base = NULL;
unsigned int MmioRead32(unsigned int offsetAddr){
	return *(volatile unsigned int *)(data_base+offsetAddr);
}
void MmioWrite32(unsigned int offsetAddr, unsigned int value){
	*(volatile unsigned int *)(data_base+offsetAddr) = value;
}

Gpio_1500a::Gpio_1500a()
{
	// TODO Auto-generated constructor stub
	pageSize = getpagesize();
	map_base = NULL;
	raw_reg_lens = 0;
}

int Gpio_1500a::delay_us(int us_n)
{
	struct timespec rqtp;
	rqtp.tv_sec  = 0;
	rqtp.tv_nsec = us_n * 1000;
	return nanosleep(&rqtp, &rqtp);
}

bool Gpio_1500a::gpio_bool_read(int mask)
{
	unsigned int value = 0;
	/* read GPI:<GPIOA bit0..3> */
	value = MmioRead32(GPIO_EXT_PORT_A);

	if(value & mask){
		return true;
	}else{
		return false;
	}
}

void Gpio_1500a::gpio_write(int wreg, int bits)
{
	unsigned int value = 0;
	value = MmioRead32(GPIO_PORTA);
	if(wreg){
		value |= (1<<(4+bits));
	}else{
		value &= ~(1<<(4+bits));
	}
	MmioWrite32(GPIO_PORTA, value);
}

unsigned int Gpio_1500a::Read_status(unsigned char command, unsigned char command_data)
{
	int i;
	static unsigned int oldStatus;
    unsigned int write_data = 0;
    unsigned int read_data = 0;
    
    write_data |= command;
    write_data = write_data << 8;
    write_data |= command_data;

	CS_0;
	Delay_Us(5);
    for (i = 0; i < 16; i++)
    {
        if (0x8000 & write_data)
            SO_1;
        else
            SO_0;
        SCLK_1;
        Delay_Us(4);
        read_data <<= 1;
        if (in_SI)
            read_data++;
		SCLK_0;
        Delay_Us(4);

        write_data <<= 1;
    }

	SCLK_0;
    CS_1;

	if(oldStatus == write_data){
		if(read_data != oldStatus){
			printf("spi w:%x, r:%x\n", write_data, read_data);
		}
	}
    return (read_data);
}

int Gpio_1500a::gpio_init()
{
	int dev_fd;
	unsigned int value = 0;
	unsigned int raw_reg_base = 0;
	size_t actualLen = 0;
	off_t actualOffset = 0;

	/* 打开/dev/mem 文件，通过DEV_MEM方式之间访问CPU寄存器，控制GPIO*/
	dev_fd = open("/dev/mem", O_RDWR | O_NDELAY);
	if (dev_fd < 0)
	{
		printf("open(/dev/mem) failed, need sudo");
		return -1;
	}
	/* 配置GPIO_A0..7、GPIO_B0..7复用为gpio功能*/
	raw_reg_base = CRU_REG_PAD_SEL;
	raw_reg_lens = 0x4;
	actualOffset = raw_reg_base / pageSize * pageSize;
	actualLen    = raw_reg_lens + raw_reg_base % pageSize;
	map_base = (unsigned char * )mmap(NULL, actualLen, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, actualOffset);
	if(map_base != NULL){
		data_base = map_base + raw_reg_base % pageSize;
		value = MmioRead32(0);
		MmioWrite32(0, value & (~(0x7<<3)));			//select GPIOA0..7、GPIO_B0..7 cru_sel_rst_state -> gpio func
		munmap(map_base, raw_reg_lens);					//解除映射关系
		printf("配置GPIO_A0..7复用为gpio功能成功\n");
	}else{
		printf("配置GPIO复用为gpio功能失败\n");
		return -2;
	}
	/* 配置GPIO_A0..7为gpio input */
	raw_reg_base = GPIO_BASE;
	raw_reg_lens = 0x1000;
	actualOffset = raw_reg_base / pageSize * pageSize;
	actualLen    = raw_reg_lens + raw_reg_base % pageSize;
	map_base = (unsigned char * )mmap(NULL, actualLen, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, actualOffset);
	if(map_base != NULL){
		data_base = map_base + raw_reg_base % pageSize;
		value = MmioRead32(GPIO_PORTA + GPIO_DATA_DIRECTION_REG);
		value |= 0xF0;														//配置GPIO_A4..7为输出
		MmioWrite32(GPIO_PORTA + GPIO_DATA_DIRECTION_REG, value & 0xFFF0);	//配置GPIO_A0..3为输入
		printf("配置GPIO_A0..3为输入成功\n");

		value = MmioRead32(GPIO_PORTB + GPIO_DATA_DIRECTION_REG);
		MmioWrite32(GPIO_PORTB + GPIO_DATA_DIRECTION_REG, value & 0xFFF0);	//配置GPIO_B0..3为输入
		printf("配置GPIO_B0..3为输入成功\n");
		return 0;
	}else{
		printf("配置GPIO输入输出功能失败\n");
		return -3;
	}
}

int Gpio_1500a::getInput()
{
	if(map_base == NULL){
		return -1;
	}
	unsigned int value = 0;
	//data_base = map_base + GPIO_BASE % pageSize;
	//value = MmioRead32(GPIO_PORTA + GPIO_DATA_DIRECTION_REG);
	//MmioWrite32(GPIO_PORTA + GPIO_DATA_DIRECTION_REG, value & 0xFF00);	//配置GPIO_A0..7为输入
	value  = MmioRead32(GPIO_EXT_PORT_A) & 0x0f;
	value |= (MmioRead32(GPIO_EXT_PORT_B) & 0x0f) << 4;
	return value;
}

Gpio_1500a::~Gpio_1500a()
{
	// TODO Auto-generated destructor stub
	if(map_base != NULL){
		munmap(map_base, raw_reg_lens);					//解除映射关系
	}
}

